/*
 * GraphicsInstance.cpp
 *
 *  Created on: Jul 6, 2009
 *      Author: kurt
 */

#include "GraphicsInstance.h"
#include <iostream>
#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <cstdlib>
using namespace std;
using namespace objdraw;

int GraphicsInstance::SCREEN_WIDTH = 480;
int GraphicsInstance::SCREEN_HEIGHT = 272;
int GraphicsInstance::SCREEN_BPP = 32;

GraphicsInstance::~GraphicsInstance() 
{
	_instance = NULL;
	SDL_QuitSubSystem(SDL_INIT_VIDEO);
}
GraphicsInstance::GraphicsInstance() 
{
	screen = NULL;
}
GraphicsInstance* GraphicsInstance::_instance = 0;// initialize pointer

GraphicsInstance* GraphicsInstance::Instance() 
{
   if (_instance == 0)
      _instance = new GraphicsInstance; // create sole instance
   return _instance; // address of sole instance
}
bool GraphicsInstance::Init3DGraphics() 
{
	atexit(SDL_Quit);
	if(SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		cout << "unable to init sdl: " << SDL_GetError() << endl;
		return false;
	}
    /* this holds some info about our display */
    const SDL_VideoInfo *videoInfo;
    /* Fetch the video info */
    videoInfo = SDL_GetVideoInfo( );
    
    if ( !videoInfo )
	{
	    cout << "Video query failed: " << SDL_GetError() << endl;
	    return false;
	}
    
    /* the flags to pass to SDL_SetVideoMode */
    videoFlags  = SDL_OPENGL;          /* Enable OpenGL in SDL */
    videoFlags |= SDL_GL_DOUBLEBUFFER; /* Enable double buffering */
    videoFlags |= SDL_HWPALETTE;       /* Store the palette in hardware */
//    videoFlags |= SDL_RESIZABLE;       /* Enable window resizing */

    /* This checks to see if surfaces can be stored in memory */
    if ( videoInfo->hw_available )
    	videoFlags |= SDL_HWSURFACE;
    else
    	videoFlags |= SDL_SWSURFACE;

    /* This checks if hardware blits can be done */
    if ( videoInfo->blit_hw )
    	videoFlags |= SDL_HWACCEL;
    /* Sets up OpenGL double buffering */
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
    
    /* get a SDL surface */
    screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, videoFlags);
    if(screen == NULL)
    {
    	cout << "unable to set video mode: " << SDL_GetError() << endl;
    	return false;
    }
	
    //init the gl
    {
        /* Enable smooth shading */
        glShadeModel( GL_SMOOTH );
        /* Set the background black */
        glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
        /* Depth buffer setup */
        glClearDepth( 1.0f );
        /* Enables Depth Testing */
        glEnable( GL_DEPTH_TEST );
        /* The Type Of Depth Test To Do */
        glDepthFunc( GL_LEQUAL );
        /* Really Nice Perspective Calculations */
        glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
        /* the alpha value blend function based on source alpha */
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        /* enable blending */
        glEnable(GL_BLEND);
    }
    
    /* resize the initial window */
	resizeWindow(SCREEN_WIDTH, SCREEN_HEIGHT);
	return false;
}
void GraphicsInstance::resizeWindow(int width, int height)
{
	/* handle resize event */
	screen = SDL_SetVideoMode( width, height, SCREEN_BPP, videoFlags );
	 /* Height / width ration */
	    GLfloat ratio;

	    /* Protect against a divide by zero */
	    if ( height == 0 )
		height = 1;

	    ratio = ( GLfloat )width / ( GLfloat )height;

	    /* Setup our viewport. */
	    glViewport( 0, 0, ( GLsizei )width, ( GLsizei )height );

	    /* change to the projection matrix and set our viewing volume. */
	    glMatrixMode( GL_PROJECTION );
	    glLoadIdentity( );

	    /* Set our perspective */
	    gluPerspective( 45.0f, ratio, 0.1f, 100.0f );

	    /* Make sure we're chaning the model view and not the projection */
	    glMatrixMode( GL_MODELVIEW );

	    /* Reset The View */
	    glLoadIdentity( );
}
SDL_Surface * GraphicsInstance::getScreen()
{
	return screen;
}
void GraphicsInstance::flipScreen()
{
	SDL_GL_SwapBuffers();
}
/** The following 2 functions for enabling and disabling 2D are COPIED
 * straight from gamedev.net =) */
//-----------------------------------------------------------------------------
// Name: glEnable2D
// Desc: Enabled 2D primitive rendering by setting up the appropriate orthographic
//		 perspectives and matrices.
//-----------------------------------------------------------------------------
void glEnable2D( void )
{
	GLint iViewport[4];

	// Get a copy of the viewport
	glGetIntegerv( GL_VIEWPORT, iViewport );

	// Save a copy of the projection matrix so that we can restore it 
	// when it's time to do 3D rendering again.
	glMatrixMode( GL_PROJECTION );
	glPushMatrix();
	glLoadIdentity();

	// Set up the orthographic projection
	glOrtho( iViewport[0], iViewport[0]+iViewport[2],
			 iViewport[1]+iViewport[3], iViewport[1], -1, 1 );
	glMatrixMode( GL_MODELVIEW );
	glPushMatrix();
	glLoadIdentity();

	// Make sure depth testing and lighting are disabled for 2D rendering until
	// we are finished rendering in 2D
	glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT );
	glDisable( GL_DEPTH_TEST );
	glDisable( GL_LIGHTING );
	/** re-enable blending ? how come i have to 
	 * should not be disabled */
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_BLEND);
}


//-----------------------------------------------------------------------------
// Name: glDisable2D
// Desc: Disables 2D rendering and restores the previous matrix and render states
//		 before they were modified.
//-----------------------------------------------------------------------------
void glDisable2D( void )
{
	glPopAttrib();
	glMatrixMode( GL_PROJECTION );
	glPopMatrix();
	glMatrixMode( GL_MODELVIEW );
	glPopMatrix();
}
void flipTextureMatrix()
{
    /** flip the texture matrix */
    glMatrixMode (GL_TEXTURE);
	glLoadIdentity ();
	glScalef (1.0f, -1.0f, 1.0f);
	glTranslatef (0.0f, -1.0f, 0.0f);
	glMatrixMode (GL_MODELVIEW);
}
